import network
import urequests
import machine
import bluetooth
import time
import gc
import ujson
import os
import socket
import _thread

# 全局变量定义
web_server_running = False  # Web服务器运行状态
web_server_thread = None    # Web服务器线程对象

try:
    with open('config.json', 'r') as f:
        config = ujson.load(f)
        WIFI_SSID = config['WIFI_SSID']
        WIFI_PASSWORD = config['WIFI_PASSWORD']
        BACKUP_WIFI_SSID = config.get('BACKUP_WIFI_SSID', "WinVIP-2.4G")
        BACKUP_WIFI_PASSWORD = config.get('BACKUP_WIFI_PASSWORD', "13512172211")
        SERVER_URL = config['SERVER_URL']
        OTA_URL = config['OTA_URL']
        CURRENT_VERSION = config['VERSION']
except:
    print('配置文件错误，使用默认值')
    WIFI_SSID = "WinVIP-2.4G"
    WIFI_PASSWORD = "13512172211"
    BACKUP_WIFI_SSID = "WinVIP-2.4G"
    BACKUP_WIFI_PASSWORD = "13512172211"
    SERVER_URL = "http://192.168.15.120:98/iot/dd2.php"
    OTA_URL = "http://gitee.com/x2in/esp32ddclient/raw/master"
    CURRENT_VERSION = '2.4'

# 初始化LED
led = machine.Pin(8, machine.Pin.OUT, value=1)

# WiFi连接状态
wifi_connected = False
retry_count = 0
current_wifi = "primary"  # 记录当前使用的WiFi

def connect_wifi():
    global wifi_connected, retry_count, current_wifi
    sta = network.WLAN(network.STA_IF)
    
    try:
        # 重置WiFi
        if sta.active():
            sta.active(False)
        time.sleep(1)
        sta.active(True)
        
        # 根据当前状态选择要连接的WiFi
        if current_wifi == "primary":
            ssid, password = WIFI_SSID, WIFI_PASSWORD
        else:
            ssid, password = BACKUP_WIFI_SSID, BACKUP_WIFI_PASSWORD
            
        # 尝试连接
        if not sta.isconnected():
            print(f"连接到 {ssid}...")
            sta.connect(ssid, password)
            
            # 等待连接，最多15秒
            for i in range(15):
                if sta.isconnected():
                    break
                time.sleep(1)
                led.value(not led.value())  # LED闪烁表示正在连接
        
        # 更新状态
        wifi_connected = sta.isconnected()
        if wifi_connected:
            print(f"WiFi已连接: {sta.ifconfig()[0]}，使用 {current_wifi} WiFi")
            retry_count = 0
            led.value(0)  # 连接成功，LED常亮
            # 连接成功后启动或重启Web服务
            start_web_server()
        else:
            print(f"{ssid} 连接失败")
            retry_count += 1
            led.value(1)  # 连接失败，LED熄灭
            
    except Exception as e:
        print(f"WiFi错误: {e}")
        wifi_connected = False
        retry_count += 1
    
    return wifi_connected

def start_web_server():
    global web_server_running, web_server_thread
    
    # 如果服务器已在运行，先停止
    if web_server_running and web_server_thread:
        stop_web_server()
    
    # 创建新线程启动Web服务器
    web_server_thread = _thread.start_new_thread(_web_server_main, ())
    print("Web服务器启动中...")

def stop_web_server():
    global web_server_running, web_server_thread
    print("正在停止Web服务器...")
    web_server_running = False
    if web_server_thread:
        # 注意：MicroPython中无法直接终止线程，这里通过标志位让线程自行退出
        try:
            # 等待线程结束
            time.sleep(1)
        except:
            pass
    web_server_thread = None

def _web_server_main():
    """Web服务器主函数（在独立线程中运行）"""
    global web_server_running
    
    s = None
    try:
        web_server_running = True
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        s.bind(('0.0.0.0', 80))
        s.listen(5)
        print("Web服务器已启动，访问设备IP地址进行配置")
        
        def generate_config_page():
            ip = network.WLAN(network.STA_IF).ifconfig()[0] if wifi_connected else "未连接"
            status = "已连接" if wifi_connected else "未连接"
            html = f"""<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>WinVIP IoT 配置</title>
    <style>
        body {{ font-family: Arial, sans-serif; max-width: 500px; margin: 0 auto; padding: 20px; }}
        h1 {{ color: #333; text-align: center; }}
        .status {{ background: #f0f0f0; padding: 15px; border-radius: 5px; margin-bottom: 20px; }}
        .form-group {{ margin-bottom: 15px; }}
        label {{ display: block; margin-bottom: 5px; font-weight: bold; }}
        input {{ width: 100%; padding: 8px; box-sizing: border-box; }}
        button {{ background: #4CAF50; color: white; border: none; padding: 10px 15px; border-radius: 4px; cursor: pointer; width: 100%; }}
    </style>
</head>
<body>
    <h1>WinVIP IoT 设备配置</h1>
    
    <div class="status">
        <p><strong>WiFi状态:</strong> {status}</p>
        <p><strong>IP地址:</strong> {ip}</p>
        <p><strong>当前版本:</strong> {CURRENT_VERSION}</p>
    </div>
    
    <form method="post" action="/save">
        <div class="form-group">
            <label for="wifi_ssid">主WiFi名称:</label>
            <input type="text" id="wifi_ssid" name="wifi_ssid" value="{WIFI_SSID}" placeholder="输入WiFi名称">
        </div>
        <div class="form-group">
            <label for="wifi_password">主WiFi密码:</label>
            <input type="password" id="wifi_password" name="wifi_password" value="{WIFI_PASSWORD}" placeholder="输入WiFi密码">
        </div>
        <div class="form-group">
            <label for="server_url">服务器URL:</label>
            <input type="text" id="server_url" name="server_url" value="{SERVER_URL}" placeholder="输入服务器地址">
        </div>
        <div class="form-group">
            <label for="ota_url">OTA更新URL:</label>
            <input type="text" id="ota_url" name="ota_url" value="{OTA_URL}" placeholder="输入OTA更新地址">
        </div>
        <button type="submit">保存配置</button>
    </form>
</body>
</html>"""
            return html
        
        def generate_reboot_page():
            html = """<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>设备重启中</title>
    <style>
        body {{ font-family: Arial, sans-serif; max-width: 400px; margin: 50px auto; text-align: center; }}
        .icon {{ font-size: 50px; color: #FF9800; margin-bottom: 20px; }}
        h1 {{ color: #333; margin-bottom: 10px; }}
        p {{ color: #666; margin-bottom: 30px; }}
        .reboot-note {{ color: #FF5722; font-weight: bold; }}
    </style>
</head>
<body>
    <div class="icon">⏳</div>
    <h1>设备正在重启</h1>
    <p>您的配置已保存，设备正在重启以应用新设置</p>
    <p class="reboot-note">请等待约10秒后重新连接设备</p>
</body>
</html>"""
            return html
        
        def parse_post_data(request):
            data = {}
            if 'POST /save' in request:
                body_start = request.find('\r\n\r\n') + 4
                if body_start > 4:
                    post_data = request[body_start:]
                    for param in post_data.split('&'):
                        if '=' in param:
                            key, value = param.split('=', 1)
                            data[key] = value.replace('+', ' ').replace('%3A', ':').replace('%2F', '/').replace('%21', '!')
            return data
        
        def save_config(data):
            global WIFI_SSID, WIFI_PASSWORD, BACKUP_WIFI_SSID, BACKUP_WIFI_PASSWORD, SERVER_URL, OTA_URL
            try:
                if 'wifi_ssid' in data:
                    WIFI_SSID = data['wifi_ssid']
                if 'wifi_password' in data:
                    WIFI_PASSWORD = data['wifi_password']
                if 'backup_wifi_ssid' in data:
                    BACKUP_WIFI_SSID = data['backup_wifi_ssid']
                if 'backup_wifi_password' in data:
                    BACKUP_WIFI_PASSWORD = data['backup_wifi_password']
                if 'server_url' in data:
                    SERVER_URL = data['server_url']
                if 'ota_url' in data:
                    OTA_URL = data['ota_url']
                
                config = {
                    'WIFI_SSID': WIFI_SSID,
                    'WIFI_PASSWORD': WIFI_PASSWORD,
                    'BACKUP_WIFI_SSID': BACKUP_WIFI_SSID,
                    'BACKUP_WIFI_PASSWORD': BACKUP_WIFI_PASSWORD,
                    'SERVER_URL': SERVER_URL,
                    'OTA_URL': OTA_URL,
                    'VERSION': CURRENT_VERSION
                }
                
                with open('config.json', 'w') as f:
                    ujson.dump(config, f)
                
                return True
            except Exception as e:
                print(f"保存配置失败: {e}")
                return False
        
        while web_server_running:
            try:
                if not wifi_connected:
                    time.sleep(1)
                    continue
                    
                conn, addr = s.accept()
                print(f"客户端连接来自: {addr}")
                request = conn.recv(1024).decode()
                
                if 'POST /save' in request:
                    data = parse_post_data(request)
                    success = save_config(data)
                    
                    if success:
                        # 显示重启提示页面
                        response = "HTTP/1.1 200 OK\r\n"
                        response += "Content-Type: text/html\r\n\r\n"
                        response += generate_reboot_page()
                        conn.send(response)
                        
                        # 延迟重启设备
                        time.sleep(1)  # 给页面加载时间
                        print("配置已保存，设备即将重启...")
                        machine.reset()
                    else:
                        # 保存失败，重定向回配置页面
                        response = "HTTP/1.1 303 See Other\r\n"
                        response += "Location: /\r\n\r\n"
                        conn.send(response)
                    
                    conn.close()
                
                elif 'GET /' in request:
                    response = "HTTP/1.1 200 OK\r\n"
                    response += "Content-Type: text/html\r\n\r\n"
                    response += generate_config_page()
                    conn.send(response)
                    conn.close()
                
            except Exception as e:
                print(f"Web服务器错误: {e}")
                try:
                    conn.close()
                except:
                    pass
    except Exception as e:
        print(f"Web服务器异常: {e}")
    finally:
        web_server_running = False
        if s:
            try:
                s.close()
            except:
                pass
        print("Web服务器已停止")

def get_server_data():
    print(f"连接服务器: {SERVER_URL}")
    try:
        mac = get_device_mac()
        print(f"设备MAC地址: {mac}")
        
        headers = {
            'User-Agent': f'winvip-device/ver: {CURRENT_VERSION} (mac: {mac})',
            'Content-Type': 'application/json',
            'Accept': 'application/json',
            'Connection': 'keep-alive',
            'Cache-Control': 'no-cache'
        }
        
        response = urequests.get(SERVER_URL, headers=headers, timeout=10)
        if response.status_code == 200:
            hex_data = response.text.strip()
            print(f"获取数据成功: {hex_data[:20]}...")
            return bytes.fromhex(hex_data)
        else:
            print(f"服务器错误: {response.status_code}")
    except Exception as e:
        print(f"请求错误: {e}")
    finally:
        if 'response' in locals():
            response.close()
    return None

def get_device_mac():
    try:
        wlan = network.WLAN(network.STA_IF)
        mac_bytes = wlan.config('mac')
        mac_str = ':'.join([f"{b:02x}" for b in mac_bytes])
        return mac_str
    except Exception as e:
        print(f"获取MAC地址失败: {e}")
        return "00:00:00:00:00:00"

def broadcast_data(data):
    try:
        ble = bluetooth.BLE()
        ble.active(True)
        if len(data) <= 31:
            ble.gap_advertise(500, adv_data=data)
            print("蓝牙广播启动")
            return True
        else:
            print("数据太长，无法广播")
    except Exception as e:
        print(f"蓝牙错误: {e}")
    return False

def safe_http_request(url, method='GET', timeout=10):
    try:
        if method == 'GET':
            response = urequests.get(url, timeout=timeout)
            if response.status_code == 200:
                return response
            else:
                print(f"服务器错误: {response.status_code}")
                response.close()
    except Exception as e:
        print(f"HTTP请求错误: {e}")
    return None

def check_ota_update():
    print(f"检查OTA更新... 当前版本: {CURRENT_VERSION}")
    try:
        version_url = OTA_URL + "/version.txt"
        response = urequests.get(version_url, timeout=10)
        
        if response.status_code == 200:
            latest_version = response.text.strip()
            print(f"最新版本: {latest_version}")
            
            if latest_version != CURRENT_VERSION:
                print("发现新版本，准备更新...")
                return latest_version
            else:
                print("已是最新版本")
        else:
            print(f"获取版本信息失败: {response.status_code}")
    except Exception as e:
        print(f"检查更新时出错: {e}")
    finally:
        if 'response' in locals():
            response.close()
    
    return None

def perform_ota_update(version):
    print(f"开始更新到版本 {version}...")
    response = safe_http_request(OTA_URL + f"/main.py")
    
    if response:
        try:
            temp_file = "firmware_temp.py"
            
            with open(temp_file, 'wb') as f:
                f.write(response.content)
            
            file_size = os.stat(temp_file)[6]
            if file_size > 0:
                print(f"固件下载成功，大小: {file_size} 字节")
                
                try:
                    with open('config.json', 'r') as f:
                        config = ujson.load(f)
                except:
                    config = {}
                
                config['VERSION'] = version
                
                with open('config.json', 'w') as f:
                    ujson.dump(config, f)
                
                os.rename(temp_file, "main.py")
                
                print("更新完成，准备重启...")
                time.sleep(2)
                machine.reset()
            else:
                print("固件文件为空，更新失败")
                try:
                    os.remove(temp_file)
                except:
                    pass
        except Exception as e:
            print(f"更新过程中出错: {e}")
            try:
                os.remove("firmware_temp.py")
            except:
                pass
        finally:
            response.close()

print(f"设备启动 v{CURRENT_VERSION}...")
connect_wifi()  # 初始连接

# 记录上次检查更新的时间
last_ota_check = 0
OTA_CHECK_INTERVAL = 3600  # 每小时检查一次更新

# 主循环
while True:
    # 检查WiFi状态
    if not wifi_connected:
        print(f"WiFi未连接，重试 ({retry_count})")
        
        if retry_count >= 3:  # 连续失败3次后切换
            if current_wifi == "primary":
                current_wifi = "backup"
                print("切换到备用WiFi")
            else:
                current_wifi = "primary"
                print("切换回主WiFi")
            retry_count = 0  # 重置重试计数
        
        connect_wifi()
        if not wifi_connected:
            wait_time = min(30, retry_count * 5)  # 指数退避
            print(f"等待 {wait_time} 秒后重试")
            for _ in range(wait_time):
                led.value(not led.value())
                time.sleep(1)
            continue
    
    # 定期检查OTA更新
    current_time = time.time()
    if current_time - last_ota_check > OTA_CHECK_INTERVAL:
        new_version = check_ota_update()
        if new_version:
            perform_ota_update(new_version)
        last_ota_check = current_time
    
    # 获取数据并广播
    data = get_server_data()
    if data:
        broadcast_data(data)
    
    # 等待下一个周期
    time.sleep(5)
